#include "Cell.h"
#include <QPainter>
#include "Line.h"
#include "../Settings/GameSettings.h"
#include "../Utils/SequentialRandom.h"

Cell::Cell(QPoint topleft, QSize size,uint nRow,uint nCol) :
    QRect(topleft,size),mOwner(Game::Unknown),mnRow(nRow),mnCol(nCol)
{        
}

uint Cell::row(){return mnRow;}

uint Cell::column(){return mnCol;}

QLine Cell::leftLine(){return QLine(topLeft(),bottomLeft());}

QLine Cell::topLine(){return QLine(topLeft(),topRight());}

QLine Cell::rightLine(){return QLine(topRight(),bottomRight());}

QLine Cell::bottomLine(){return QLine(bottomLeft(),bottomRight());}

Game::Player Cell::owner(){return mOwner;}

bool Cell::addLine(Line *pLine)
{
    if((!isLineAdded(pLine)) &&  mLines.count() < 4){
        mLines.append(pLine);
        pLine->addContainer(this);
        addDot(pLine->dot1());
        addDot(pLine->dot2());

        if(mLines.count() == 4){
            mOwner = pLine->owner();
        }

        return true;
    }

    return false;
}

bool Cell::removeLine(Line *pLine)
{
    for(int i = 0; i < mLines.count(); i++){
        Line *pTmpLine = mLines.at(i);

        if(pTmpLine->isSame(pLine->line())){
            removeDot(pTmpLine->dot1());
            removeDot(pTmpLine->dot2());
            pTmpLine->removeContainer(this);
            mLines.removeOne(pTmpLine);
            this->mOwner = Game::Unknown;
            return true;
        }
    }

    return false;
}

bool Cell::isLineAdded(Line *pLine)
{
    return isLineAdded(pLine->line());
}

bool Cell::isLineAdded(QLine line)
{
    for(int i = 0; i < mLines.count(); i++){
        if(mLines.at(i)->isSame(line)){
            return true;
        }
    }

    return false;
}

int Cell::lineAddedCount(){return mLines.count();}

bool Cell::addDot(Dot *pDot)
{
    if((!isDotAdded(pDot)) && mDots.count() < 4){
        mDots.append(pDot);

        return true;
    }

    return false;
}

bool Cell::removeDot(Dot *pDot)
{
    for(int i = 0; i < mDots.count(); i++){
        Dot *pTmpDot = mDots.at(i);

        if(pTmpDot->isSame(pDot->point())){
            mDots.removeOne(pTmpDot);
            return true;
        }
    }

    return false;
}

bool Cell::isDotAdded(Dot *pDot)
{
    return isDotAdded(pDot->point());
}

bool Cell::isDotAdded(QPoint pos)
{
    for(int i = 0; i < mDots.count(); i++){
        if(mDots.at(i)->isSame(pos)){
            return true;
        }
    }

    return false;
}

int Cell::dotAddedCount(){return mDots.count();}

bool Cell::nearToMe(QPoint pos)
{
    bool bRet = topLeft() == pos || topRight() == pos || bottomRight() == pos || bottomLeft() == pos ||
            this->contains(pos);
    return bRet;
}

bool Cell::isCompleted() {return mLines.count() == 4;}

QRect Cell::rect()
{
    return QRect(topLeft(),size());
}

void Cell::draw(QPainter *pDC)
{
    pDC->setPen(GameSettings::me()->playerColor(owner()));
    pDC->drawRect(rect());
}

void Cell::drawOwner(QPainter *pDC)
{
    if(!isCompleted()){
        return;
    }

    int nLineLen = height() / 2;
    int nFlagWidth = width() / 4;
    int nFlagHeight = height() / 6;
    int nTopShipt = height() / 4;
    int nLeftShift = (width() - nFlagWidth ) / 2;
    QPoint ptUp = topLeft() + QPoint(nLeftShift,nTopShipt);
    QPoint ptDown = topLeft() + QPoint(nLeftShift,nTopShipt + nLineLen);

    pDC->setPen(GameSettings::me()->playerColor(owner()));
    pDC->drawLine(ptUp,ptDown);

    pDC->setBrush(GameSettings::me()->brush(owner()));
    pDC->drawRect(QRect(ptUp,QSize(nFlagWidth,nFlagHeight)));
}

bool Cell::isACorner(Dot *pDot)
{    
    return pDot ? isACorner(pDot->point()) : false;
}

bool Cell::isACorner(QPoint pos)
{
    return topLeft() == pos || topRight() == pos
            || bottomRight() == pos || bottomLeft() == pos;
}

bool Cell::isASide(Line *pLine)
{
    return pLine ? isASide(pLine->line()) : false;
}

bool Cell::isASide(QLine line)
{
    return Line::isSame(leftLine(),line) || Line::isSame(topLine(),line) ||
           Line::isSame(rightLine(),line) || Line::isSame(bottomLine(),line);
}

bool Cell::isSame(QRect rect)
{
    return isACorner(rect.topLeft()) && isACorner(rect.topRight()) &&
            isACorner(rect.bottomLeft()) && isACorner(rect.bottomRight());
}

bool Cell::isSame(Element *pElem, bool bByValue)
{
    Cell *pCell = dynamic_cast<Cell*>(pElem);

    if(pCell){
        if(bByValue){
            return isSame(pCell->rect());
        }
        else{
            return this == pCell;
        }
    }
    else{
        return false;
    }
}

QList<QLine> Cell::sides()
{
    QList<QLine> sides;
    sides.append(leftLine());
    sides.append(topLine());
    sides.append(rightLine());
    sides.append(bottomLine());

    return sides;
}

QList<QLine> Cell::getSidesThatNotAddYet()
{
    QList<QLine> lines;
    QList<QLine> linesToCheck = sides();

    SequentialRandom rnd(linesToCheck.count() - 1,0);

    for(int i = 0; i < linesToCheck.count(); i++){
        QLine line = linesToCheck.at(rnd.next());

        if(!isLineAdded(line)){
            if(!lines.contains(line)){
                lines.append(line);
            }
        }
    }

    return lines;
}

bool Cell::isAdjacent_Straight(Cell *pCell)
{
    return (this->row() == pCell->row() && qAbs(int(this->column()) - int(pCell->column())) == 1) ||
            (this->column() == pCell->column() && qAbs(int(this->row()) - int(pCell->row())) == 1);
}

QLine Cell::commonSide(Cell *pCell)
{
    QList<QLine> mySides = sides();
    QList<QLine> hisSides = pCell->sides();

    for(int i = 0; i < mySides.count(); i++){
        for(int j = 0; j < hisSides.count(); j++){
            if(Line::isSame(mySides.at(i),hisSides.at(j))){
                return mySides.at(i);
            }
        }
    }

    return QLine();
}

bool Cell::isWinableNow()
{
    return lineAddedCount() == 3 && lineAddedCount() < 4;
}
